<?php

declare(strict_types=1);

/**
 * @Author:     Frank
 * @contact     frank_hhm@163.com
 * @Date:       2023-01-12 09:41:26
 * @Last Modified time: 2023-01-31 17:22:30
 */
namespace addon\wechat\services;

use addon\wechat\services\WeappOpenApiService;
use frank\exception\CommonException;
use addon\wechat\constants\ErrorCode;
use app\common\dao\wechat\UserDao;

use app\common\services\user\RegisterService;
use app\common\services\user\UserService;
use think\facade\Db;

/**
 * 微信登录
 * Class LoginAuthService
 */
class LoginAuthService  extends \frank\base\BaseService
{
    protected $param;

    protected $appType;

    protected $openidKey; 

    protected $openidKeyArr = [
        'weapp'=>'weapp_openid',
        'wechat'=>'wechat_appid'
    ];

    /**
     * LoginAuthService constructor.
     * @param UserDao $dao
     */
    public function __construct(UserDao $dao,array $data){
        $this->dao = $dao;
        $this->param = $data;
        $this->appType = $data['app_type'] ?? 'weapp';
        $this->openidKey = $this->openidKeyArr[$this->appType];
    }

	public function login(){
		$weData = $this->getUserData();
        $appType = $this->appType;
        
		if(empty($weData['openid'])){
            throw new CommonException('授权失败');
        }

        $existMap['unionid'] = $weData['unionid'] ?? '';
        $existMap[$this->openidKey] = $weData['openid'];
        $userId = 0;
        // 用户是否已存在
        $wechat = $this->dao->search($existMap)->find();
		if($wechat == null){
            $registerService = RegisterService::instance();
            $userId = $this->transaction(function () use ($existMap,$weData,$appType,$registerService) {
                $id = $registerService->authRegister($weData,$appType);
            	$this->dao->save(array_merge(
                    ['user_id'=>$id],
                    $existMap
                ));
                return $id;
            });
		}else{
            $userId = $wechat['user_id'];
        }
        return [$userId,$this->appType];
	}

    /**
     * 获取微信用户解密信息
     */
	public function getUserData(){
		$apiService = WeappOpenApiService::instance();
		$res = $apiService->jscode2session(
			$this->param['code'] ?? ''
		);
		if(empty($res['session_key'])){
            throw new CommonException('授权失败');
        }
        $weData = $this->decrypt($res['session_key'],$this->param['encryptedData'],$this->param['iv']);
        $weData = json_decode($weData,true);
        return array_merge(  $res , $weData);
	}

	/**
     * 微信信息解密
     * @param  string  $encryptedData 在小程序中获取的encryptedData
     * @param  string  $iv 在小程序中获取的iv
     * @return array 解密后的数组
     */
    public function decrypt(string $sessionKey ,string $encryptedData,string $iv ){
        
        if (strlen($sessionKey) != 24) {
        	ErrorCode::get(-41001);
        }
        $aesKey = base64_decode($sessionKey);

        if (strlen($iv) != 24) {
        	ErrorCode::get(-41002);
        }
        $aesIV = base64_decode($iv);

        $aesCipher = base64_decode($encryptedData);

        $result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
        if(!$result){
			throw new CommonException('微信用户信息解密失败');
        }
        $dataObj = json_decode( $result );
        if( $dataObj  == NULL )
        {
        	ErrorCode::get(-41003);
        }
        if( $dataObj->watermark->appid !=  sysconf('wechat_appid'))
        {
        	ErrorCode::get(-41004);
        }
        return $result;
    }

     /**
     * 请求过程中因为编码原因+号变成了空格
     * 需要用下面的方法转换回来
     */
    public function defineStrReplace($data)
    {
        return str_replace(' ','+',$data);
    }

}

